# -*- coding: utf-8 -*-
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
# odoo v2.0
# QQ:35350428
# 邮件:35350428@qq.com
# 手机：13584935775
# 作者：'Amos'
# 公司网址： www.odoo360.com
# Copyright 中亿丰数字科技有限公司 2012-2022 Amos
# 日期：2022-06-08
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

from odoo import models, api
from lxml.builder import E
from odoo.exceptions import UserError, ValidationError
import json
from collections import defaultdict, OrderedDict


class BaseModel(models.AbstractModel):
    _inherit = 'base'
    _is_worflow = False  # 创建工作流


    @api.model
    def _compute_confirm_uid(self):
        """
        #当前审核人
        #串签，并签，汇签
        #按钮权限放在后台判断
        :return:
        """
        for line in self:
            workflow_confirm_uid = False #当前审批人
            workflow_look = False #是否显示按钮
            workflow_id = False #工作流审批节点

            # TODO(amos): 代码校验用户
            analyse = self.action_code_before(line) #个性化校验用户是不是可以进行流程
            if analyse.get('errmsg') == 'yes':
                domain = [
                    ('res_model', '=', line._name),
                    ('res_id', '=', line.id),
                    ('state', '=', '等待审批'),
                ]
                records = self.env['workflow.info'].sudo().search(domain, order="sequence asc, id asc")

                if records:
                    for work in records:
                        if work.type == '串签':
                            workflow_confirm_uid = work.user_id.id
                            workflow_id = work.id
                            workflow_look = True
                        if work.type in ['汇签', '并签']:
                            # 当前用户是不是在流程中
                            workflow = records.filtered(lambda t: t.user_id.id == self._uid)
                            if not workflow:
                                workflow_confirm_uid = False
                                workflow_look = False
                                workflow_id = False
                            else:
                                workflow_confirm_uid = self._uid
                                workflow_look = True
                                workflow_id = workflow.id
                        break
                    # 是不是有多人审核
                    if workflow_look:
                        if self._uid != workflow_confirm_uid:
                            workflow_look = False
                else:
                    if line.state in ['新建', '草稿','draft']:
                        workflow_look = True

            line.update({'workflow_confirm_uid': workflow_confirm_uid, 'workflow_look': workflow_look,
                         'workflow_id': workflow_id})



    #::::工作流确认

    #:::通过审核
    def button_workflow_approval(self, _context=None):
        """
        界面通用审核
        <button name="button_workflow_approval" string="审核" type="object"
                                attrs="{'invisible': [('workflow_look','!=',True)]}"
                                context="{'wkf': 'workflow_ok,workflow_no','type_flows': 'button'}"
                                class="btn-primary"/>
        @param _context:
        @return:
        """
        context = dict(self._context or {})
        context['one'] = 'one'
        """
        #当前审核人
        #串签，并签，汇签
        #按钮权限放在后台判断
        :return:
        """
        #::::判断这个工作流是不是已存在存在执行提醒 并刷新 当前用户流程已存在，或已在其它地方登陆并操作
        workflow_type = '串签'
        if self.workflow_id:
            workflow_type = self.workflow_id.type
            if self.workflow_id.state != '等待审批' and self.workflow_confirm_uid.id != self._uid:
                raise UserError('警告：当前审批流程已发生改变，新刷新当前页面！')

        workflow_id = 0
        last_user = False  # 是否最后一个审核人了
        mult_confirm = False  # 是否多人审核：如果不是就不显示下级审核人选项
        stop_flow = False  # 是否最后一次审核节点

        if workflow_type == '串签':
            domain = [
                ('res_model', '=', self._name),
                ('res_id', '=', self.id),
                ('state', '=', '等待审批'),
            ]
            records = self.env['workflow.info'].sudo().search(domain, order="sequence asc, id desc")

            if len(records._ids) > 1:
                mult_confirm = True  # 如果是隐藏下级审核人
            if len(records._ids) <= 1:
                last_user = True

            #:::审核人内是不是有我
            if records:
                user = records.filtered(lambda t: t.user_id.id == self.env.user.id)
                if not user:
                    raise UserError('警告：当前审批流程，不存在你的审批！')
                else:
                    workflow_id = records[0].id
                    if records[0].user_id.id != self.env.user.id:
                        raise UserError('警告：请等待 %s 审核后' % records[0].user_id.name)

        elif workflow_type == '汇签':
            mult_confirm = False  # 是否多人审核
            last_user = True  # 是否最后一个审核人了
            #:::找当前流程里是不是有我
            domain = [
                ('res_model', '=', self._name),
                ('res_id', '=', self.id),
                ('state', '=', '等待审批'),
                ('user_id', '=', self.env.user.id),
            ]
            records = self.env['workflow.info'].sudo().search(domain, order="sequence asc, id desc")
            if len(records._ids) >= 1:
                last_user = True
                workflow_id = records[0].id
            else:
                raise UserError('警告：当前审批流程已发生改变，新刷新当前页面！')

        elif workflow_type == '并签':
            #:::找当前流程里是不是有我
            domain = [
                ('res_model', '=', self._name),
                ('res_id', '=', self.id),
                ('state', '=', '等待审批'),
            ]
            records = self.env['workflow.info'].sudo().search(domain, order="sequence asc, id desc")
            if records:
                if len(records._ids) > 1:
                    mult_confirm = True  # 如果是隐藏下级审核人
                if len(records._ids) <= 1:
                    last_user = True

                #:::审核人内是不是有我
                if records:
                    user = records.filtered(lambda t: t.user_id.id == self.env.user.id)
                    if not user:
                        raise UserError('警告：当前审批流程，不存在你的审批！')
                    else:
                        workflow_id = records[0].id

        res_id = False


        #:::::使用工作流来主导下级审批人
        if mult_confirm == False:
            workflow_user_ids = []  # 查询出的流程节点
            user_ids = []

            domain = [('model', '=', self._name), ('user_id', '=', self._uid)]
            workflow = self.env['workflow'].sudo().search(domain, order="id desc", limit=1)
            if workflow:
                line = workflow.node_ids.filtered(
                    lambda o: o.state_form == self.state)
                if len(line) > 1:
                    raise UserError('警告：系统流程配置错误！')
                else:
                    context['process_id'] = line.id  # 记录使用的流程ID
                    stop_flow = line.is_stop
                    workflow_type = line.attr #workflow.node 默认
                    domain = []
                    if line.domain:
                        import ast
                        domain_new = ast.literal_eval(line.domain)
                        domain = domain_new
                    if line.type == '自定义':
                        if line.is_company:
                            domain_new = ('company_id', '=', self.env.user.company_id.id)
                            domain.append(domain_new)

                        if line.is_department:
                            if self.env.user.department_id:
                                domain_new = ('department_id', '=', self.env.user.department_id.id)
                                domain.append(domain_new)
                        workflow_user_ids = self.env['res.users'].sudo().search(domain)
                    elif line.type == '固定审核人':
                        workflow_user_ids = line.users_ids
                    elif line.type == '权限组':
                        for group in line.groups_ids:
                            if group.users:
                                user_ids = user_ids + list(group.users._ids)

            else:
                domain = [('model', '=', self._name)]
                process = self.env['workflow'].sudo().search(domain, order="id desc", limit=1)
                line = process.node_ids.filtered(lambda o: o.state_form == self.state)
                if len(line) > 1:
                    raise UserError('警告：系统流程配置错误！')
                else:
                    context['process_id'] = line.id
                    stop_flow = line.is_stop
                    workflow_type = line.attr  # workflow.node 默认
                    domain = []
                    if line.domain:
                        import ast
                        domain_new = ast.literal_eval(line.domain)
                        domain = domain_new
                    if line.type == '自定义':
                        if line.is_company:
                            domain_new = ('company_id', '=', self.env.user.company_id.id)
                            domain.append(domain_new)

                        if line.is_department:
                            if self.env.user.department_id:
                                domain_new = ('department_id', '=', self.env.user.department_id.id)
                                domain.append(domain_new)
                        workflow_user_ids = self.env['res.users'].sudo().search(domain)
                    elif line.type == '固定审核人':
                        workflow_user_ids = line.users_ids
                    elif line.type == '权限组':
                        for group in line.groups_ids:
                            if group.users:
                                user_ids = user_ids + list(group.users._ids)


            if workflow_user_ids:
                for user in workflow_user_ids:
                    user_ids.append(user.id)

            #::::去重
            if user_ids:
                #:::如果存在历史就添加历史再加上现在的
                if res_id:
                    for line in check.check_user_ids:
                        user_ids.append(line.user_id.id)
                    res_id = False

                user_ids = list(set(user_ids))

            context['workflow_user_ids'] = user_ids

            if user_ids:
                lines = []
                sequence = 1
                for user_id in user_ids:
                    pram = {
                        'user_id': user_id,
                        'sequence': sequence,
                    }
                    lines.append((0, 0, pram))
                    sequence += sequence + 1
                context['default_check_user_ids'] = lines
        else:
            pass

        context['mult_confirm'] = mult_confirm  # 是不是流程中节点审核
        context['workflow_id'] = workflow_id  # 准备更新的状态的工作流
        context['last_user'] = last_user  # 是否最后一个审核人了
        context['workflow_type'] = workflow_type  # 工作流类型
        context['stop_flow'] = stop_flow  # 是不是最后一道

        form_id = self.env.ref('workflow.view_form_workflow_approval_wizard_01').id
        return {'type': 'ir.actions.act_window',
                'res_model': 'workflow.approval',
                'view_mode': 'form',
                'views': [(form_id, 'form')],
                'target': 'new',
                'res_id': res_id,
                'context': context,
                'flags': {'form': {'action_buttons': True}}}

    #::确认
    def workflow_ok(self, _context=None):
        """
        设计思想
        用户在界面点击审批或其它按钮，会传递
        wkf：object_ok,object_no
        type_flows：button
        button_name：button
        form_state：state 一般默认当前状态
        to_state：'已确认' 一般是如果确认后应该到达的状态
        next_state：'已完成' 当前审核流程完成时为下一个审批人传递审核节点
        以上参数支持缺省参数
        :param _context: 审核相关的所有条件都在上下文里传递，如果要改变条件可以在具体的Button里改变
        :return:
        """

        #:::::::判断用户工作流是不是存在，不存在就不执行
        lines = self.browse(int(self._context['active_id']))

        # TODO(amos): 代码校验用户
        analyse = self.action_code_inside(lines)  # 个性化校验用户是不是可以进行流程

        if analyse.get('errmsg') == 'yes':
            start_state = lines.state
            context = dict(_context or {})
            create_flow = False  # 下级审批流程是不是已创建
            # 判断当前工作流，如果是第一个人创建每一个节点
            process = None
            if _context['stop_flow'] == True:
                process = self.env['workflow.node'].sudo().browse(self._context['process_id'])
                lines.workflow_three(lines, process, context, _context)  # TODO(amos): 最后一次审批流程
            else:
                if not self.workflow_id:
                    if not context.get('process_id'):
                        if _context['is_process_node'] == True and context.get('stop_flow', False) == False:
                            #:::流程中节点审批
                            pass
                    else:
                        process = self.env['workflow.node'].sudo().browse(self._context['process_id'])
                        lines.workflow_one(lines, process, context, _context)  # TODO(amos): 第一次工作流
                else:
                    process = self.env['workflow.node'].sudo().browse(self._context['process_id'])
                    lines.workflow_two(lines, process, context, _context)  # TODO(amos): 流程审批

            #:::更新用户流程 如果 workflow_id = 0 就不执行
            self.env['workflow.info'].write_workflow(lines, context.get('approval_state', ''), context)
            #::::发送相关消息  找对象最早的一条记录，进行更新消息
            #::::发消息给选定的人 来创建工单
            # url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
            # check_user_ids
            # domain = [('model', '=', lines._name), ('res_id', '=', lines.id)]
            # message = self.env['mail.message'].sudo().search(domain, order="id desc", limit=1)
            # if message:
            #     if len(context['messages_partner_ids']) > 0:
            #         for partner_id in context['messages_partner_ids']:
            #             values = {
            #                 'mail_message_id': message.id,
            #                 'res_partner_id': partner_id,
            #             }
            #             self.env['mail.notification'].create(values)
            # else:
            # 创建消息并加新
            if context.get('messages_partner_ids'):

                notification_values = []
                for partner_id in context['messages_partner_ids']:
                    pram = {
                        'res_partner_id': partner_id,
                        # 'mail_id': mail.id,
                        'notification_type': 'inbox',  # email
                        'is_read': False,
                        'notification_status': 'ready',
                    }
                    notification_values.append((0, 0, pram))

                if len(context['messages_partner_ids']) > 0:
                    # 阅知
                    messages_partner_name = " ".join(context['messages_partner_name'])

                    url  = '<a href="/web#model=%s&amp;id=%s" class="o_Message_originThreadLink">查看阅知</a>' % (self._context['active_model'],self._context['active_id'])

                    values = {
                        'record_name': lines.name,
                        'subject': lines._description,
                        'body': "<strong><font color=\"#FF0000\">%s:</font></strong>\n%s<br/><strong>审批建议/处理意见:</strong>%s" % (url, messages_partner_name, context['message'] or ''),
                        'message_type': 'notification',
                        'res_id': lines.id,
                        'model': lines._name,
                        'subtype_id': 2,  # id=2 待办
                        'author_id': self.env.user.partner_id.id,
                        # 'notified_partner_ids': [(6, 0, context['messages_partner_ids'])],
                        'notification_ids': notification_values,
                    }
                    message = self.env['mail.message'].with_context(message_type='notification').create(values)

                    # model_id = self.env['ir.model']._get(lines._name).id
                    # if len(context['messages_users_ids']) > 0:
                    #     for user_id in context['messages_users_ids']:
                    #         #::::::::创作并分配一个任务
                    #         activity = {
                    #             'type': '',
                    #             'line': lines,
                    #             'user_id': user_id,
                    #             'summary': '任务',
                    #             'note':  context['message'],
                    #             'id_object': '%s,%s' % (lines._name, lines.id),
                    #             # 'ref_men': 'hd_base.menu_0',  # 顶部菜单
                    #         }
                    #         self.env.user.add_mail_activity(activity)
        return True

    def workflow_one(self, lines, process, context, _context):
        create_flow = process.is_stop
        if _context['is_process_node'] == True and context.get('stop_flow', False) == False:
            #:::流程中节点审批
            pass
        else:
            #:::记录提交人信息
            if context['last_user'] == True:
                if process != None:
                    if process.state_form in ['新建']:
                        self.env['workflow.info'].create_workflow_ok(lines, process.state_form,
                                                                     process.state_to, context)

            #::::根据菜单来确认执行Button事件
            if hasattr(self, process.button_name):
                # 调用多重方法
                run_self = self.env[self._context['active_model']]

                vv = {}
                vv['state'] = context.get('next_state', '')
                vv['create_flow'] = create_flow

                _context['state_to'] = process.state_to
                _context['create_flow'] = create_flow

                param = getattr(run_self, process.button_name, vv)(_context)
                if param:
                    end_state = param['state']
                    create_flow = param['create_flow']
                    context['workflow_ids'] = param.get('workflow_ids', [])
                else:
                    end_state = vv['state']
                    create_flow = vv['create_flow']
            else:
                raise UserError('警告：[%s] 对象不存在！' % self._context['button_name'])

            #:::创建下级审核人列表
            #:::如果不相等说明系统有子流程，可以在当前流程中判断 并生成下级流程

            if create_flow == False:
                domain = [
                    ('res_model', '=', lines._name),
                    ('res_id', '=', lines.id)
                ]
                records = self.env['workflow.info'].search(domain, order="sequence asc, id desc", limit=1)
                parent_id = False
                if records:
                    parent_id = records.id
                self.env['workflow.info'].create_workflow(lines, parent_id, process.next_id.id,
                                                          process.next_id.state_form,
                                                          process.next_id.state_to,
                                                          context)
        return True

    def workflow_two(self, lines, process, context, _context):
        create_flow = process.is_stop
        if _context['is_process_node'] == True and context.get('stop_flow', False) == False:
            #:::流程中节点审批
            pass
        else:
            #::::根据菜单来确认执行Button事件
            if hasattr(self, process.button_name):
                # 调用多重方法
                run_self = self.env[self._context['active_model']]
                vv = {}
                vv['state'] = context.get('next_state', '')
                vv['create_flow'] = create_flow

                _context['state_to'] = process.state_to
                _context['create_flow'] = create_flow
                param = getattr(run_self, process.button_name, vv)(_context)
                if param:
                    end_state = param['state']
                    create_flow = param['create_flow']
                    context['workflow_ids'] = param.get('workflow_ids', [])
                else:
                    end_state = vv['state']
                    create_flow = vv['create_flow']
            else:
                raise UserError('警告：[%s] 对象不存在！' % self._context['button_name'])

            #:::创建下级审核人列表
            #:::如果不相等说明系统有子流程，可以在当前流程中判断 并生成下级流程
            #::::查询下级工作流

            if create_flow == False:
                domain = [
                    ('res_model', '=', lines._name),
                    ('res_id', '=', lines.id)
                ]
                records = self.env['workflow.info'].search(domain, order="sequence asc, id desc", limit=1)
                parent_id = False
                if records:
                    parent_id = records.id
                self.env['workflow.info'].create_workflow(lines, parent_id, process.next_id.id,
                                                          process.next_id.state_form,
                                                          process.next_id.state_to,
                                                          context)

        return True

    def workflow_three(self, lines, process, context, _context):
        create_flow = process.is_stop
        if _context['is_process_node'] == True and context.get('stop_flow', False) == False:
            #:::流程中节点审批
            pass
        else:
            #::::根据菜单来确认执行Button事件
            if hasattr(self, process.button_name):
                # 调用多重方法
                run_self = self.env[self._context['active_model']]
                vv = {}
                vv['state'] = context.get('next_state', '')
                vv['create_flow'] = create_flow

                _context['state_to'] = process.state_to
                _context['create_flow'] = create_flow
                param = getattr(run_self, process.button_name, vv)(_context)
            else:
                raise UserError('警告：[%s] 对象不存在！' % self._context['button_name'])
        return True

    def order_confirm(self, _context=None):
        if not self:
            self = self.browse(_context.get('active_id'))
        values = {
            'state': _context['state_to'],
        }
        self.write(values)
        param = {'state': _context['state_to'], 'create_flow': _context['create_flow']}
        return param

    #::拒绝
    def workflow_no(self, context=None):
        """
        拒绝执行事件
        :param context:
        :return:
        """

        context = dict(self._context or {})
        lines = self.browse(int(self._context['active_id']))
        lines.with_context(context).action_home()

        #:::删除无效的默认值
        self.env['workflow.approval'].sudo().browse(context['workflow_id']).unlink()
        return True

    def action_home(self):

        body = '[拒绝] %s' % self._context['message']
        try:
            self.message_post(body=body)
        except:
            _logger.info("[%s]没有安装社交mail" % self._name)

        # TODO(amos): 更新工作流
        self.workflow_id.write({'state': '拒绝', 'note': self._context['message']})
        # TODO(amos): 关闭其它工作流
        user = self.workflow_ids.filtered(lambda t: t.state == '等待审批')
        user.write({'state': user.parent_id.refuse, 'end_date': datetime.datetime.utcnow()})

        state = self._context.get('state', '新建')

        if self._context.get('wkf'):
            if self.workflow_id.process_id:
                process = self.workflow_id.process_id #工作流
                version_id = datetime.datetime.utcnow()
                objflow = self.env['workflow.info']
                workflow = None

                # 如果设置以我为准 解决多版本问题
                if process.go_next_id:
                    domain=[('res_model', '=', self.workflow_id.res_model),('res_id', '=', self.workflow_id.res_id),('process_id', '=', process.go_next_id.id),('state', '=', '同意')]
                    obj = objflow.search(domain, order="id desc", limit=1)

                    domain=[('version_id', '=', obj.version_id),('res_model', '=', self.workflow_id.res_model),('res_id', '=', self.workflow_id.res_id),('process_id', '=', process.go_next_id.id),('state', '=', '同意')]
                    workflow = objflow.sudo().search(domain, order="sequence asc, id desc")
                elif process.parent_id:
                    domain = [('res_model', '=', self.workflow_id.res_model), ('res_id', '=', self.workflow_id.res_id),
                              ('process_id', '=', process.parent_id.id), ('state', '=', '同意')]
                    workflow = objflow.sudo().search(domain,order="sequence asc, id desc")

                else:
                    state = self.workflow_id.process_id.refuse

                if workflow:
                    for v in workflow:
                        if v.start_state not in ['新建','草稿','draft']:
                            state = v.start_state
                            values = {
                                'type': v.type,
                                'version_id': version_id,
                                'res_model': v.res_model,
                                'res_id': v.res_id,
                                'model_id': v.model_id.id,
                                'name': v.name,
                                'user_id': v.user_id.id,
                                'end_date': datetime.datetime.utcnow(),
                                'start_state': v.start_state,
                                'end_state': v.end_state,
                                'note': '',
                                'sequence': v.sequence,
                                'parent_id': v.parent_id.id,
                                'process_id': v.process_id.id,
                            }
                            self.env['workflow.info'].create(values).id

        return self.write({'state': state})

    def action_reset(self):
        """
        重置单据
        :return:
        """
        return self.write({'state': '新建'})

    def action_code_before(self,kw):
        """
        审批之前执行Python 代码
        :return:
        """

        data = {
            'errmsg': 'yes', #yes no
            "data": '',
            'message': '校验成功!'}

        return data
    def action_code_inside(self,kw):
        """
        每次执行Python 代码
        :return:
        """
        context = dict(self._context or {})


        data = {
            'errmsg': 'yes', #yes no
            "data": '',
            'message': '校验成功!'}

        return data

    def action_code_after(self,kw):
        """
        结束后执行Python 代码
        :return:
        """
        return {}
     #::::::新工作流结束